package com.dfbz.dao.base;

import com.dfbz.annotation.MyField;
import com.dfbz.annotation.MyTable;
import com.dfbz.model.User;
import com.dfbz.utils.JDBCUtil;
import jdk.nashorn.internal.scripts.JD;
import org.apache.commons.dbutils.BasicRowProcessor;
import org.apache.commons.dbutils.GenerousBeanProcessor;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class BaseDao<T> {

    private final Class<T> aClass;
    private final String tableName;
    private final String keyName;

    public BaseDao(Class<T> aClass) {
        this.aClass = aClass;
        MyTable annotation = aClass.getDeclaredAnnotation(MyTable.class);
        if (null != annotation) {
            tableName = annotation.value();
            keyName = annotation.key();
        } else {
            tableName = "null";
            keyName = "id";
        }
    }

    public List<T> findByCol(String key, String value) {
        String sql = "select * from " + tableName + " where " + key + " = ?";
        QueryRunner qr = new QueryRunner(JDBCUtil.getDataSource());
        List<T> list = new ArrayList<>();
        try {
            list = qr.query(sql, new BeanListHandler<>(aClass), value);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return list;
    }

    public List<T> findByCols(String condition, Map<String, Object> map) {
        StringBuilder sb = new StringBuilder();
        sb.append("select * from ").append(tableName).append(" where ");
        if (null == map || map.isEmpty()) {
            sb.delete(sb.lastIndexOf("where"), sb.length());
        } else {
            // 遍历Map集合，动态拼接条件
            Set<String> keySet = map.keySet();
            for (String key : keySet) {
                sb.append(key).append(" = '").append(map.get(key)).append("' = ").append(condition).append(" ");
            }
            sb.delete(sb.lastIndexOf(condition), sb.length());
        }
        List<T> list = new ArrayList<>();
        QueryRunner qr = new QueryRunner(JDBCUtil.getDataSource());
        try {
            list = qr.query(sb.toString(), new BeanListHandler<>(aClass));
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return list;
    }

    public int save(Object obj) {
        int row = 0;
        Class<?> aClass = obj.getClass();
        Field[] fields = aClass.getDeclaredFields();

        StringBuilder sb = new StringBuilder();
        sb.append("insert into ").append(tableName).append(" values(");
        for (int i = 0; i < fields.length; i++) {
            if (i == fields.length - 1) {
                // 遍历到最后一个
                sb.append("?)");
            } else {
                sb.append("?,");
            }
        }

        QueryRunner qr = new QueryRunner(JDBCUtil.getDataSource());
        try {
            Object[] params = new Object[fields.length];
            for (int i = 0; i < fields.length; i++) {
                String fieldName = fields[i].getName();
                String methodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
                Method method = aClass.getDeclaredMethod(methodName);
                Object value = method.invoke(obj);
                params[i] = value;
            }
            row = qr.update(sb.toString(), params);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return row;
    }

    public int update(Object obj) {
        int row = 0;
        StringBuilder sb = new StringBuilder();
        sb.append("update ").append(tableName).append(" set ");

        Class<?> aClass = obj.getClass();
        Field[] fields = aClass.getDeclaredFields();
        for (Field field : fields) {
            String colName = field.getName();
            MyField myField = field.getAnnotation(MyField.class);
            if (null != myField) {
                colName = myField.value();
            }
            sb.append(colName).append(" = ?, ");
        }
        sb.delete(sb.lastIndexOf(","),sb.length());
        sb.append("where ").append(keyName).append(" = ?");

        QueryRunner qr = new QueryRunner(JDBCUtil.getDataSource());
        try {
            Object[] params = new Object[fields.length + 1];
            Object id = null;
            for (int i = 0; i < fields.length; i++) {
                Field field = fields[i];
                String fieldName = field.getName();
                String colName = field.getName();
                MyField myField = field.getAnnotation(MyField.class);
                if (null != myField) {
                    colName = myField.value();
                }
                String methodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
                Method method = aClass.getDeclaredMethod(methodName);
                Object value = method.invoke(obj);
                if (colName.equals(keyName)){
                    id = value;
                }
                params[i] = value;
            }
            params[fields.length] = id;
            row = qr.update(sb.toString(), params);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return row;
    }

    public T findById(Object id){
        String sql = "select * from " + tableName + " where " + keyName + " = ?";
        QueryRunner qr = new QueryRunner(JDBCUtil.getDataSource());
        GenerousBeanProcessor bean = new GenerousBeanProcessor();
        BasicRowProcessor processor = new BasicRowProcessor(bean);
        T obj = null;
        try {
            obj = qr.query(sql, new BeanHandler<>(aClass,processor), id);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return obj;
    }

    public void findById(){

    }
    public int deleteById(Object id){
        int row = 0;
        String sql = "delete from " + tableName + " where " + keyName + " = ? ";
        QueryRunner qr = new QueryRunner(JDBCUtil.getDataSource());
        try {
            row = qr.update(sql, id);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return row;
    }
}
